﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Runtime.InteropServices;
using System.Windows.Forms;
using System.ComponentModel;

namespace Hi_Baidu.Hooks
{
    /// <summary>
    ///     提供了线程钩子的相关操作
    /// </summary>
    public class ThreadHook
    {
         /// <summary>
        /// 钩子属性区
        /// </summary>

        //键盘钩子代码
        [Description("钩子类型 - 2 - 线程钩子")]
        private int wm_keyboard_ll;
        public int WM_KEYBOARD_LL
        {
            get { return wm_keyboard_ll; }
            set { wm_keyboard_ll = value; }
        }

        //用于比较的键值
        [Description("用于比较的键值")]
        private Keys contorl_keys;
        public Keys Contorl_keys
        {
            get { return contorl_keys; }
            set { contorl_keys = value; }
        }

        //程序集名称
        [Description("要引用的程序集名称")]
        String programcollection_name;
        public String Programcollection_name
        {
            get { return programcollection_name; }
            set { programcollection_name = value; }
        }

        //方法名称
        [Description("要引用的方法名称")]
        String method_name;
        public String Method_name
        {
            get { return method_name; }
            set { method_name = value; }
        }

        //命令空间 + 类名称
        [Description("要引用的对象，形式：命名空间.类名")]
        String namespace_class_name;
        public String Namespace_class_name
        {
            get { return namespace_class_name; }
            set { namespace_class_name = value; }
        }

        //控制键
        [Description("控制键 ： Ctrl / Alt / Shift")]
        Keys modifier_keys;
        public Keys Modifier_keys
        {
            get { return modifier_keys; }
            set { modifier_keys = value; }
        }


        IntPtr hHook = IntPtr.Zero;
        public delegate int HookProc(int nCode, IntPtr wParam, IntPtr lParam);
        HookProc KeyboardHookProcedure;

        // 安装钩子
        [DllImport("user32.dll", CharSet = CharSet.Auto, CallingConvention = CallingConvention.StdCall)]
        public static extern IntPtr SetWindowsHookEx(int idHook, HookProc lpfn, IntPtr hInstance, int threadId);
        // 卸载钩子
        [DllImport("user32.dll", CharSet = CharSet.Auto, CallingConvention = CallingConvention.StdCall)]
        public static extern IntPtr UnhookWindowsHookEx(IntPtr idHook);
        // 继续下一个钩子
        [DllImport("user32.dll", CharSet = CharSet.Auto, CallingConvention = CallingConvention.StdCall)]
        public static extern int CallNextHookEx(IntPtr idHook, int nCode, IntPtr wParam, IntPtr lParam);
        // 取得当前线程编号
        [DllImport("kernel32.dll")]
        static extern int GetCurrentThreadId();

        /// <summary>
        /// 此方法负责响应键盘事件 [键盘钩子 - 线程]
        /// </summary>
        /// <param name="nCode"></param>
        /// <param name="wParam"></param>
        /// <param name="lParam"></param>
        /// <returns></returns>
        private int KeyboardHookProc(int nCode, IntPtr wParam, IntPtr lParam)
        {
            if (nCode >= 0)
            {
                //得到键值
                Keys keys = (Keys)wParam.ToInt32();
                //判断
                if (keys == Contorl_keys && Control.ModifierKeys == this.modifier_keys)
                {
                    OnOnInputKey(new EventArgs());
                }
                return 1;
            }
            return CallNextHookEx(this.hHook, nCode, wParam, lParam);
        }

        /// <summary>
        /// 此方法负责安装钩子 
        /// </summary>
        public bool Install_HooK()
        {
            if (this.hHook == IntPtr.Zero)
            {
                KeyboardHookProcedure = new HookProc(KeyboardHookProc);
                //安装钩子
                this.hHook = SetWindowsHookEx(this.wm_keyboard_ll, KeyboardHookProcedure, IntPtr.Zero, GetCurrentThreadId());
                if (this.hHook == IntPtr.Zero)
                {
                    return false;
                }
                else
                {
                    return true;
                }
            }
            return false;
        }

        /// <summary>
        /// 此方法负责卸载钩子
        /// </summary>
        /// <returns></returns>
        public bool UnStall_Hook()
        {
            if (this.hHook != IntPtr.Zero)
            {
                //卸载钩子
                this.hHook = UnhookWindowsHookEx(this.hHook);
                if (this.hHook == IntPtr.Zero)
                {
                    return true;
                }
                else
                {
                    return false;
                }
            }
            return false;
        }


        #region 'OnInputKey' event definition code

        // Private delegate linked list (explicitly defined)
        private EventHandler<System.EventArgs> OnInputKeyEventHandlerDelegate;

        /// <summary>
        ///     TODO: Describe the purpose of this event here
        /// </summary>
        public event EventHandler<System.EventArgs> OnInputKey
        {
            // Explicit event definition with accessor methods
            add
            {
                OnInputKeyEventHandlerDelegate = (EventHandler<System.EventArgs>)Delegate.Combine(OnInputKeyEventHandlerDelegate, value);
            }
            remove
            {
                OnInputKeyEventHandlerDelegate = (EventHandler<System.EventArgs>)Delegate.Remove(OnInputKeyEventHandlerDelegate, value);
            }
        }

        /// <summary>
        ///     This is the method that is responsible for notifying
        ///     receivers that the event occurred
        /// </summary>
        protected virtual void OnOnInputKey(System.EventArgs e)
        {
            if (OnInputKeyEventHandlerDelegate != null)
            {
                OnInputKeyEventHandlerDelegate(this, e);
            }
        }

        #endregion //('OnInputKey' event definition code)

    }
    [StructLayout(LayoutKind.Sequential)]
    public struct KBDLLHOOKSTRUCT
    {
        public int vkCode;
        public int scanCode;
        public int flags;
        public int time;
        public int dwExtraInfo;
    }
}
